//--------------------------------------------------------------------------------------------
//
//
//      Component name  : fpadd_normalize
//      Author          : 
//      Company         : 
//
//      Description     : 
//
//
//--------------------------------------------------------------------------------------------


module FPadd_normalize(EXP_in, SIG_in, EXP_out, SIG_out, zero);
   input [7:0]   EXP_in;
   input [27:0]  SIG_in;
   output [7:0]  EXP_out;
   reg [7:0]     EXP_out;
   output [27:0] SIG_out;
   reg [27:0]    SIG_out;
   output        zero;
   
   
   reg [7:0]     EXP_lshift;
   reg [7:0]     EXP_rshift;
   reg [27:0]    SIG_lshift;
   wire [27:0]   SIG_rshift;
   wire [7:0]    add_in;
   wire          cin;
   wire [4:0]    count;
   reg           isDN;
   reg           shift_RL;
   wire [26:0]   word;
   wire          zero_int;
   reg           denormal;
   reg [4:0]     lshift_cnt;
   
   assign SIG_rshift = {1'b0, SIG_in[27:2], (SIG_in[1] & SIG_in[0])};
   
   assign add_in = {3'b000, count};

   //exp -127---128
   wire  [8:0]    EXP_in_value ;
   assign  EXP_in_value   =  {1'd0,EXP_in} - 9'h7f  ;
   
   wire  [8:0]    abs_EXP_in_value ;
   //assign  abs_EXP_in_value =  (~EXP_in_value+1)   ;
   //assign  abs_EXP_in_value =  EXP_in + 8'h81  ;
   assign  abs_EXP_in_value =  9'd512 - EXP_in_value  +  add_in ;
  
   always @(count or EXP_in)
      //if ($signed(count) > $signed(EXP_in))
      //if (  (add_in >    (~EXP_in_value+1)  ) && EXP_in_value[7] )
      //if (  (add_in >    abs_EXP_in_value  ) && ~EXP_in_value[7]  )
      //begin
      //   //lshift_cnt = EXP_in[4:0] - 1;
      //   //lshift_cnt =  EXP_in_value[4:0];
      //   lshift_cnt =   abs_EXP_in_value  ;
      //   denormal = 1'b1;
      //end
     // if ( (abs_EXP_in_value>127)&& (EXP_in_value[8])  ) begin 
     //     lshift_cnt = 'd0 ;
     //     denormal   = 1'b1;
     // end
     // else
      begin
         lshift_cnt = count;
         denormal = 1'b0;
      end
   
   
   always @(isDN or shift_RL or EXP_lshift or EXP_rshift or EXP_in or SIG_lshift or SIG_rshift or SIG_in or denormal)
      if (isDN == 1'b1)
      begin
         EXP_out = 8'h00;
         SIG_out = SIG_in;
      end
      else
         if (shift_RL == 1'b1)
         begin
            if (SIG_in[27] == 1'b1)
            begin
               EXP_out = EXP_rshift;
               SIG_out = SIG_rshift;
            end
            else
            begin
               EXP_out = EXP_in;
               SIG_out = SIG_in;
            end
         end
         else
            if (denormal == 1'b1)
            begin
               //EXP_out = {8{1'b0}};
               EXP_out = EXP_in;
               SIG_out = SIG_lshift;
            end
            else
            begin
               EXP_out = EXP_lshift;
               SIG_out = SIG_lshift;
            end
   
   assign zero = zero_int & (~SIG_in[27]);
   
   assign word = SIG_in[26:0];
   
   
   always @(SIG_in or EXP_in)
      if (SIG_in[27] == 1'b0 & SIG_in[26] == 1'b0 & (EXP_in == 8'h01))
      begin
         isDN = 1'b1;
         shift_RL = 1'b0;
      end
      else if (SIG_in[27] == 1'b0 & SIG_in[26] == 1'b0 & (EXP_in != 8'h00))
      begin
         isDN = 1'b0;
         shift_RL = 1'b0;
      end
      else
      begin
         isDN = 1'b0;
         shift_RL = 1'b1;
      end
   
   assign cin = 1'b0;
   
   
   reg [8:0]     t0;
      reg [8:0]     sum;
      reg [7:0]     din_l;

   always @(EXP_in)
   begin: I4combo     
      din_l = EXP_in;
      t0 = {din_l[7], din_l};
      sum = ($signed(t0) + 1'b1);
      EXP_rshift = (sum[7:0]);
   end
   
   reg [4:0]     stemp;
      reg [27:0]    dtemp;
      reg [27:0]    temp;
      integer       i;

   always @(SIG_in or lshift_cnt)
   begin: I1combo    
      temp = {28{1'bX}};
      stemp = lshift_cnt;
      temp = SIG_in;
      for (i = 4; i >= 0; i = i - 1)
      begin
         if (i < 5)
         begin
            if (stemp[i] == 1'b1 )
            begin
               dtemp = {28{1'b0}};
               //dtemp[27:2 ** i] = temp[27 - 2 ** i:0];
               if(i==4)  dtemp[27:16] = temp[27 - 16:0];
               else if (i==3)  dtemp[27:8] = temp[27 - 8:0];
               else if (i==2)  dtemp[27:4] = temp[27 - 4:0];
               else if (i==1)  dtemp[27:2] = temp[27 - 2:0];
               else            dtemp[27:1] = temp[27 - 1:0];  
            end
            else if (stemp[i] == 1'b0 )
               dtemp = temp;
            else
               dtemp = {28{1'bX}};
         end
         else begin
            if (stemp[i] == 1'b1 )
               dtemp = {28{1'b0}};
            else if (stemp[i] == 1'b0 )
               dtemp = temp;
            else
               dtemp = {28{1'bX}};
          end
         temp = dtemp;
      end
      SIG_lshift = dtemp;
   end
   

         reg [8:0]     mw_I2t0;
      reg [8:0]     mw_I2t1;
      reg [8:0]     diff;
      reg           borrow;

   
   always @(EXP_in or add_in or cin)
   begin: I2combo
      mw_I2t0 = {EXP_in[7], EXP_in};
      mw_I2t1 = {add_in[7], add_in};
      borrow = cin;
      diff = $signed(mw_I2t0) - $signed(mw_I2t1) - borrow;
      EXP_lshift = (diff[7:0]);
   end
   
   
   FPlzc I0(.word(word), .zero(zero_int), .count(count));
   
endmodule
